﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;

using SecuritiesAnalysis.Common;

namespace SecuritiesAnalysis.CurrentData
{
    public class DataSpider:IDisposable
    {
        private List<T_StockCode> CodeList;
        private List<T_HistoryPrice> historyList;
        private SecuritiesAnalysisDataContext ctx;
        private List<StringBuilder> sb;

        private List<string> queryList;
        private List<string> results;

        private T_HistoryPrice mod;

        private string prefixsh = "sh";
        private string prefixsz = "sz";
        private string endfix = ",";

        public DataSpider()
        {
            ctx = new SecuritiesAnalysisDataContext();
        }

        /// <summary>
        /// 解压数据
        /// </summary>
        private string[] DecompressData(string data)
        {
            char[] c = { ';' };
            string[] results = data.Split(c);

            return results;
        }

        /// <summary>
        /// 格式化数据字符串
        /// </summary>
        private T_HistoryPrice FormatData(string content)
        {
            MatchCollection mc;

            Regex r = new Regex(@"(?<=\042).*(?=\042)"); //定义一个Regex对象实例
            mc = r.Matches(content);

            char[] c = { ',' };
            string[] results = (mc[0].Value).Split(c);

            #region comment
            /** 0："大秦铁路"，股票名字；
             * 1："27.55″，今日开盘价；
             * 2："27.25″，昨日收盘价；
             * 3："26.91″，当前价格；
             * 4："27.55″，今日最高价；
             * 5："26.20″，今日最低价；
             * 6："26.91″，竞买价，即"买一"报价；
             * 7："26.92″，竞卖价，即"卖一"报价；
             * 8："22114263″，成交的股票数，由于股票交易以一百股为基本单位，所以在使用时，通常把该值除以一百；
             * 9："589824680″，成交金额，单位为"元"，为了一目了然，通常以"万元"为成交金额的单位，所以通常把该值除以一万；
             * 10："4695″，"买一"申请4695股，即47手；
             * 11："26.91″，"买一"报价；
             * 12："57590″，"买二"
             * 13："26.90″，"买二"
             * 14："14700″，"买三"
             * 15："26.89″，"买三"
             * 16："14300″，"买四"
             * 17："26.88″，"买四"
             * 18："15100″，"买五"
             * 19："26.87″，"买五"
             * 20："3100″，"卖一"申报3100股，即31手；
             * 21："26.92″，"卖一"报价
             * (22, 23), (24, 25), (26,27), (28, 29)分别为"卖二"至"卖四的情况"
             * 30："2008-01-11″，日期；
             * 31："15:05:32″，时间；
             * */
            #endregion

            mod = new T_HistoryPrice();
            mod.StockCode = GetStockCode(content);
            mod.Date = Convert.ToDateTime(results[30] + " " + results[31]);
            mod.OpeningPrice = Convert.ToDecimal(results[1]);//日期
            mod.ClosingPrice = Convert.ToDecimal(results[3]);//当前价格，模拟收盘价
            mod.CeilingPrice=Convert.ToDecimal(results[4]);//今日最高价
            mod.FloorPrice = Convert.ToDecimal(results[5]);//今日最低价
            mod.Volume = Convert.ToInt32(results[8]);//成交数

            return mod;
        }

        /// <summary>
        /// 将所有股票当前价存入数据库
        /// </summary>
        public bool UpdateCurrentPrice()
        {
            //////////////////先删除再添加////////////////////
            try
            {
                historyList = ctx.T_HistoryPrices.Where(o => o.Date > DateTime.Today).ToList();
                ctx.T_HistoryPrices.DeleteAllOnSubmit(historyList);
                ctx.SubmitChanges();
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }

            queryList = BuildQueryList();

            try
            {
                foreach (string query in queryList)
                {
                    historyList = new List<T_HistoryPrice>();

                    string source = GetJSbyWC(query);
                    results = DecompressData(source).ToList();
                    results.RemoveAt(results.Count - 1);
                    
                    foreach (string result in results)
                    {
                        historyList.Add(FormatData(result));
                    }

                    ctx.T_HistoryPrices.InsertAllOnSubmit(historyList);
                    ctx.SubmitChanges();
                }
                return true;
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }

        }

        /// <summary>
        /// 构造查询字符串
        /// </summary>
        /// <returns></returns>
        private List<string> BuildQueryList()
        {
            CodeList = ctx.T_StockCodes.Where(c => c.Enabled == true).ToList();

            sb = new List<StringBuilder>();
            int num = Convert.ToInt32(Math.Ceiling((Convert.ToDouble(CodeList.Count) / 100.0)));

            for (int i = 0; i < num; i++)//初始化sb列表
            {
                StringBuilder s = new StringBuilder();
                sb.Add(s);
            }

            for (int i = 0; i < num; i++)//循环每个sb
            {
                //sb[i];
                foreach (T_StockCode code in CodeList.Skip(100 * i).Take(100))//分页构建每个sb
                {
                    if (code.StockCode < 599999)//深市
                    {
                        sb[i].Append(prefixsz);
                    }
                    else//沪市
                    {
                        sb[i].Append(prefixsh);
                    }
                    sb[i].Append(code.StockCode.ToString("000000"));
                    sb[i].Append(endfix);
                }
            }

            List<string> querylist = new List<string>();

            foreach (StringBuilder ss in sb)
            {
                querylist.Add(ss.ToString());
            }

            return querylist;
        }

        /// <summary>
        /// 从结果字符串中获取股票代码
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        private int GetStockCode(string info)
        {
            MatchCollection mc;

            Regex r = new Regex(@"\d{6}(?=[=])"); //定义一个Regex对象实例
            mc = r.Matches(info);
            return Convert.ToInt32(mc[0].Value); //将匹配的字符串添在字符串数组中
        }

        /// <summary>
        /// 将某只股票当前价存入数据库
        /// </summary>
        public bool UpdateCurrentPrice(int stockcode)
        {
            //////////////////先删除再添加////////////////////
            try
            {
                ctx.T_HistoryPrices.DeleteOnSubmit(ctx.T_HistoryPrices.Where(o => o.Date > DateTime.Today && o.StockCode == stockcode).FirstOrDefault());
                ctx.SubmitChanges();
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }

            try
            {
                StringBuilder querybuilder = new StringBuilder();
                if (stockcode < 599999)//深市
                {
                    querybuilder.Append(prefixsz);
                }
                else//沪市
                {
                    querybuilder.Append(prefixsh);
                }
                querybuilder.Append(stockcode.ToString("000000"));
                querybuilder.Append(endfix);

                string source = GetJSbyWC(querybuilder.ToString());

                ctx.T_HistoryPrices.InsertOnSubmit(FormatData(source));
                ctx.SubmitChanges();

                return true;
            }
            catch (Exception e)
            {
                Log.OutputError(e.Message);
                return false;
            }
        }
        
        #region 获取新浪清单，每秒4.5个，二方法耗时基本相等

        /// <summary>
        /// 通过webclient获取数据
        /// </summary>
        private string GetJSbyWC(string code)
        {
            using (WebClient wc = new WebClient())
            {
                Stream resStream = wc.OpenRead("http://hq.sinajs.cn/list=" + code);
                StreamReader sr = new StreamReader(resStream, System.Text.Encoding.Default);
                string result = sr.ReadToEnd();
                resStream.Close();
                return result;
            }
        }

        /// <summary>
        /// 通过http获取数据
        /// </summary>
        private string GetJSbyHTTP(string code)
        {

            WebRequest request = WebRequest.Create("http://hq.sinajs.cn/list=" + code);
            WebResponse response = request.GetResponse();
            Stream resStream = response.GetResponseStream();
            StreamReader sr = new StreamReader(resStream, System.Text.Encoding.Default);
            string result = sr.ReadToEnd();
            resStream.Close();
            sr.Close();

            return result;
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!m_disposed)
            {
                if (disposing)
                {
                    // Release managed resources
                }

                // Release unmanaged resources

                m_disposed = true;
            }
        }

        ~DataSpider()
        {
            Dispose(false);
        }
  
        private bool m_disposed;

        #endregion
    }

}
